I love the smell of UnrealEd crashing in the morning. – tarquin

Legacy:TABname Completion

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search

TABname Completion mimics that uncommonly-known mIRC command that fills in a person's name, depending on what text they enter (when you press the TAB key).

This code is/will be in a version of Esc sometime soon – I have placed this in my UTConsole class, in the 'Typing' state, under the 'KeyEvent' function. When entering part of any Player's name (case-sensitive), it will complete the Player's name.

To Do[edit]

  • Thanks to Mychaeel's code, it now cycles through similar names. And it works perfectly - no-one prove me wrong.

Implementation[edit]

The following implementation in UnrealScript has been created by DJPaul and Mychaeel for the Esc mod. Feel free to use and modify.

state Typing
{
    //Process 'String' from right-to-left, looking for the first 'LookFor'.
    function int FindRightMost(string String, string LookFor)
    {
        local int i;
 
        for (i=len(String)-1; i>=0; i--)
        {
            if ( mid(String, i, 1) == LookFor )
            {
                return i+1;
            }
        }
 
        //Rogue-value.
        return 667;
    }
 
    event bool KeyEvent( EInputKey Key, EInputAction Action, FLOAT Delta )
    {
        local string TextNameCompletedFirst, TextNameCompletedSuccessor;
        local string ThisPlayerName; //To cut down on long statements below.
        local int RightSpace, i;
 
 
        if (Action!=IST_Press)
            return false;
 
        if ((Key == IK_Tab) && (Viewport.Actor != none))
        {
            // String comparisons (equality, alphabetical order) shall be case-insensitive.
            // Use ~= for equality and Caps() for alphabetical order in UnrealScript.
 
            RightSpace = FindRightMost(TypedStr, " ");
            if (RightSpace == 667)
                return false;
 
            if (TextNamePrefix == "")
            {
                TextNamePrefix = Right(TypedStr, len(TypedStr)-RightSpace);
                TextNameCompletedPrev = "";
            }
 
            if (Viewport.Actor.GameReplicationInfo != none)
            {
                for (i=0; i<32; i++)
                {
                    if (Viewport.Actor.GameReplicationInfo.PRIArray[i] != none)
                    {
                        ThisPlayerName = Viewport.Actor.GameReplicationInfo.PRIArray[i].PlayerName;
 
                        if (left(ThisPlayerName, len(TextNamePrefix)) == TextNamePrefix)
                        {
                            // Save the first matching player name in alphabetical order in case we don't
                            // find an alphabetical successor of TextNameCompletedPrev.
                            if ((TextNameCompletedFirst == "") || (ThisPlayerName < TextNameCompletedFirst))
                                TextNameCompletedFirst = ThisPlayerName;
 
                            if (TextNameCompletedPrev != "")
                            {
                                // Save the player name we're looking at if it is one of TextNameCompletedPrev's
                                // alphabetical successors (and a better match than the last one we found).
                                if (ThisPlayerName > TextNameCompletedPrev)
                                    if ((TextNameCompletedSuccessor == "") || (ThisPlayerName < TextNameCompletedSuccessor))
                                        TextNameCompletedSuccessor = ThisPlayerName;
                            }
                        }
                    }
                }
 
                if (TextNameCompletedSuccessor == "")                     // no alphabetical successor found?
                    TextNameCompletedSuccessor = TextNameCompletedFirst;  // start over from first
 
                TextNameCompletedPrev = TextNameCompletedSuccessor;     // save for next iteration
 
                // TextNameCompletedSuccessor now contains the next matching name. Replace the
                // partially entered name by the content of TextNameCompletedSuccessor.
                TypedStr = left(TypedStr, (RightSpace-1)) $ " " $ TextNameCompletedSuccessor;
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            TextNamePrefix = ""; //Make code reevaluate the entered prefix.
 
            return Super.KeyEvent(Key, Action, Delta);
        }
    }
}

Mychaeel: Wouldn't you like case-insensitivity for that? (That's why I mentioned a ~= b and Caps(a) < Caps(b) in that comment – it would be handy.)

DJPaul: Good point - will make it so that it converts them both to uppercase first, just as easy as using a ~# b. I'll upload the tested code this evening.

Mychaeel: ~= strikes me as more elegant (and more concise), that's all. After all its express purpose is to compare strings without case sensitivity.

xX)(Xx: Clearer instructions for where to place the code would be nice ;) or if anyone has the time, a proper .u file, as this is something which a lot of the UT community will want

DJPaul: This went into Esc, a UT1998 mod. IIRC, I put it into our custom Console class. As to where you want it to go, if it's in a dialogue box, you're going to want to do put it in the equivalent of a onKeyEvent method. If you want it from the "T"alk line, you're going to have to replace the class that is done in; I don't know if this is still in Console, I never looked.

El Muerte: it's ExtendedConsole for UT200x. Btw, UT1998 mod? I hope you mean UT'99 ;) My UTelAdSE and UnGateway mods also have tab completion to complete commands, but it works more like the Bash shell (prints a list of available options).

xX)(Xx: Will this work server side? Or will the latest anti-cheats scream HACK! ? ;)

EricBlade: I had to change all occurences of "Viewport" to "ViewportOwner", and add "local string TextNamePrefix, TextNameCompletedPrev;" to the KeyEvent function


----

Category ... erm. Useful Function? Function? Snippet? something, anyway